#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/reboot.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>


static const struct option OPTIONS[] = {
  { "update_package", required_argument, NULL, 'u' },
  { "type", required_argument, NULL, 't' },
  { "wipe_data", no_argument, NULL, 'w' },
  { "factory_restore", no_argument, NULL, 'f' },
  { NULL, 0, NULL, 0 },
};


struct bootloader_message {
    char command[32];
    char status[32];
    char recovery[1024];
};


size_t
strlcpy(char *dst, const char *src, size_t siz)
{
	char *d = dst;
	const char *s = src;
	size_t n = siz;

	/* Copy as many bytes as will fit */
	if (n != 0) {
		while (--n != 0) {
			if ((*d++ = *s++) == '\0')
				break;
		}
	}

	/* Not enough room in dst, add NUL and traverse rest of src */
	if (n == 0) {
		if (siz != 0)
			*d = '\0';		/* NUL-terminate dst */
		while (*s++)
			;
	}

	return(s - src - 1);	/* count does not include NUL */
}

size_t
strlcat(char *dst, const char *src, size_t siz)
{
	char *d = dst;
	const char *s = src;
	size_t n = siz;
	size_t dlen;

	/* Find the end of dst and adjust bytes left but don't go past end */
	while (n-- != 0 && *d != '\0')
		d++;
	dlen = d - dst;
	n = siz - dlen;

	if (n == 0)
		return(dlen + strlen(s));
	while (*s != '\0') {
		if (n != 1) {
			*d++ = *s;
			n--;
		}
		s++;
	}
	*d = '\0';

	return(dlen + (s - src));	/* count does not include NUL */
}


#define COMMAND_FILE     "command"
static const int MAX_ARG_LENGTH = 4096;
static const int MAX_ARGS = 100;

static void
check_and_fclose(FILE *fp, const char *name) {
    fflush(fp);
    if (ferror(fp)) printf("Error in %s\n(%s)\n", name, strerror(errno));
    fclose(fp);
}


static void
get_args(int *argc, char ***argv) {
    char *argv0 = (*argv)[0];

    struct bootloader_message boot;
    memset(&boot, 0, sizeof(boot));

    // --- if that doesn't work, try the command file
    if (*argc <= 1) {
        FILE *fp = fopen(COMMAND_FILE, "r");
        if (fp != NULL) {
            *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
            (*argv)[0] = argv0;  // use the same program name

            char buf[MAX_ARG_LENGTH];
            for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
                if (!fgets(buf, sizeof(buf), fp)) break;
                (*argv)[*argc] = strdup(strtok(buf, "\n"));  // Strip newline.
            }

            check_and_fclose(fp, COMMAND_FILE);
            printf("Got arguments from %s\n", COMMAND_FILE);
        }
    }

    // --> write the arguments we have back into the bootloader control block
    // always boot into recovery after this (until finish_recovery() is called)
    //strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
    //strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
    int i;
    for (i = 1; i < *argc; ++i) {
        printf("argc = %d\n", *argc);
        printf("argv[%d] = %s\n",i , (*argv)[i]);
        strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
        strlcat(boot.recovery, "\n", sizeof(boot.recovery));
    }
    printf("boot.recovery = %s\n", boot.recovery);

}

int main()
{
    int i = 0;
    int argc = 0;
    char **argv = (char **)malloc(1024);
    get_args(&argc, &argv);
    printf("~~~~~~~~~~~\n");
    for (i = 1; i < argc; ++i) {
        printf("argc = %d\n", argc);
        printf("argv[%d] = %s\n",i , argv[i]);
    }


    const char *type = NULL;
    const char *update_package = NULL;
    int wipe_data = 0, factory_restore = 0;

    int arg;
    while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
        switch (arg) {
        case 'u': update_package = optarg; break;
        case 't': type = optarg; break;
        case 'w': wipe_data = 1; break;
        case 'f': factory_restore = 1; break;
        case '?':
            printf("Invalid command argument\n");
            continue;
        }
    }

    printf("update_package = %s\n", update_package);
    printf("type = %s\n", type);
    printf("wipe_data = %d\n", wipe_data);
    printf("factory_restore = %d\n", factory_restore);

    return 0;
}

